package com.mbigger.netty.ch5;

import com.mbigger.netty.ch5.duplex.DuplexHandlerA;
import com.mbigger.netty.ch5.duplex.DuplexHandlerB;
import com.mbigger.netty.ch5.duplex.DuplexHandlerC;
import com.mbigger.netty.ch5.in.InBoundHandlerA;
import com.mbigger.netty.ch5.in.InBoundHandlerB;
import com.mbigger.netty.ch5.in.InBoundHandlerC;
import com.mbigger.netty.ch5.out.OutBoundHandlerA;
import com.mbigger.netty.ch5.out.OutBoundHandlerB;
import com.mbigger.netty.ch5.out.OutBoundHandlerC;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class NettyServer {

    /**
     * 在端口绑定失败之后，重新调用自身方法，并且把端口号加一
     * 
     * @param serverBootstrap
     *            TCP Server 启动辅助类
     * @param port
     *            需要绑定的端口号
     */

    private static void bind(final ServerBootstrap serverBootstrap, final int port) {
        serverBootstrap.bind(port).addListener(new GenericFutureListener<Future<? super Void>>() {
            public void operationComplete(Future<? super Void> future) {
                ChannelFuture channelFuture = (ChannelFuture) future;
                Channel channel = channelFuture.channel();
                if (future.isSuccess()) {
                    log.info("绑定成功, 本地地址[{}]", channel.localAddress());
                } else {
                    log.error("端口[{}]绑定失败, 失败原因: {}", port, future.cause().getMessage());
                    bind(serverBootstrap, port + 1);
                }
            }
        });
    }

    public static void main(String[] args) {

        int port = 49664;

        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();

        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.handler(new ChannelInitializer<NioServerSocketChannel>() {
            protected void initChannel(NioServerSocketChannel ch) {
                log.info("服务端启动中...");
            }
        });
        serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    protected void initChannel(NioSocketChannel ch) {
                        log.info("init channel !");
                        // inBound，处理读数据的逻辑链
                        ch.pipeline().addLast(new InBoundHandlerA());
                        ch.pipeline().addLast(new InBoundHandlerB());
                        ch.pipeline().addLast(new InBoundHandlerC());

                        // outBound，处理写数据的逻辑链
                        ch.pipeline().addLast(new OutBoundHandlerA());
                        ch.pipeline().addLast(new OutBoundHandlerB());
                        ch.pipeline().addLast(new OutBoundHandlerC());

                        // 复合处理器
                        ch.pipeline().addLast(new DuplexHandlerA());
                        ch.pipeline().addLast(new DuplexHandlerB());
                        ch.pipeline().addLast(new DuplexHandlerC());

                    }
                });

        bind(serverBootstrap, port);

    }
}
